//
// Created by LiuYou on 2021/7/24.
//

/*
 * 静态内存和栈内存以及动态内存(堆内存)。
 * 
 * 最安全的分配和使用动态内存(堆内存)的方法是调用一个名为 make_shared<>(); 的标准库函数。
 * 此函数在动态内存中(堆内存)中分配一个对象并初始化它, 返回指向此对象的 shared_ptr。
 *
 * shared_ptr的拷贝和赋值:
 * shared_ptr使用了引用计数技术, 所以它拷贝的时候引用计数加1, 赋值给其它shared_ptr的时候, 等号左侧递减没有赋值之前的管理的资源的引用计数,
 * 因为它不再管理了。而等号右边的引用计数加1, 因为等号左边的shared_ptr指向了它管理的资源。
 *
 * 直接管理内存: new/delete。malloc/free。
 * 相对于智能指针, 使用这两个运算符管理内存非常容易出错。使用智能指针可以依赖类对象拷贝、赋值和销毁操作的任何默认定义(即编译器合成的函数)。而使用
 * new和delete就不行。因此使用智能指针的程序更容易编写和调试。
 *
 * unique_ptr:
 * 某个时刻只能有一个unique_ptr指向一个给定的对象。当unique_ptr被销毁时, 它指向的对象也被销毁。
 * make_unique<>();
 *
 * 传递unique_ptr参数和返回unique_ptr: 
 * 不能拷贝unique_ptr规则有一个例外: 我们可以拷贝或赋值一个将要被销毁的unique_ptr。
 * 如下函数例子。clone();
 * 但是这种情况下, 编译器执行的是一种特殊的"拷贝", 即移动。
 *
 * weak_ptr:
 * weak_ptr指向由一个shared_ptr指向的对象(管理的对象)。但是不会改变shared_ptr的引用计数。
 * weak_ptr是辅助shared_ptr而存在的。
 *
 * allocator类, 标准库allocator类帮助我们将内存分配和对象构造分离开来。这一部分内容很多, 暂时先不学习。
 */




#include <cstdlib>
#include <memory>
#include <iostream>


// 下面这两个函数都是可以的。在这两个函数中, 编译器执行的是一种特殊的"拷贝", 即移动。
std::unique_ptr<int> clone(int integer) {
    // ...
    return std::make_unique<int>( integer );
}

//std::unique_ptr<int> clone(int integer) {
//    std::unique_ptr<int> ret( new int( integer ));
//    // ...
//    return ret;
//}


int main() {
    int integer = 44;
    std::shared_ptr<int> ptrInteger = std::make_shared<int>( 44 );
    std::cout << "&integer: " << &integer << std::endl;
    std::cout << "ptrInteger.get(): " << ptrInteger.get() << std::endl;
    std::shared_ptr<int> ptrInteger1( std::move( ptrInteger ));
    ptrInteger = nullptr;
    // Clang-Tidy: Local copy 'ptrInteger2' of the variable 'ptrInteger1' is never modified; consider avoiding the copy
    // Clang-Tidy：永远不会修改变量“ptrInteger1”的本地副本“ptrInteger2”；考虑避免复制
    std::shared_ptr<int> ptrInteger2( ptrInteger1 );

    std::cout << "===========================================================" << std::endl;

    // 下面这条注释语句是错误的。
    std::unique_ptr<int> pInt = std::make_unique<int>( 100 );
    std::cout << "*pInt: " << *pInt << std::endl;

    // unique_ptr不支持拷贝构造函数和拷贝赋值运算符。
//    std::unique_ptr<int> p = pInt;
    // unique_ptr支持移动构造和移动赋值运算符。
    std::unique_ptr<int> p = std::move( pInt );
    std::cout << "*p: " << *p << std::endl;

    std::unique_ptr<int> ptr( p.release());
    if (p == nullptr) {
        std::cout << "p 现在是空指针" << std::endl;
    }

    std::cout << "*ptr: " << *ptr << std::endl;

    std::unique_ptr<int> uniquePtr = clone( 22 );
    std::cout << "*uniquePtr: " << *uniquePtr << std::endl;

    std::cout << "===========================================================" << std::endl;

    {
        using std::make_shared;
        std::shared_ptr<int> sharedPtr = make_shared<int>( 44 );
        std::weak_ptr<int> weakPtr( sharedPtr );
        std::cout << "weakPtr.use_count(): " << weakPtr.use_count() << std::endl;
        std::shared_ptr<int> sharedPtr1 = sharedPtr;
        std::cout << "weakPtr.use_count(): " << weakPtr.use_count() << std::endl;
        sharedPtr1 = nullptr;
        std::cout << "weakPtr.use_count(): " << weakPtr.use_count() << std::endl;
        std::shared_ptr<int> sharedPtr2 = weakPtr.lock();
        if (sharedPtr2 != nullptr) {
            std::cout << "*sharedPtr2: " << *sharedPtr2 << std::endl;
        }
        sharedPtr = nullptr;
        sharedPtr2 = nullptr;
        std::cout << "sharedPtr: " << sharedPtr << std::endl;
        std::shared_ptr<int> sharedPtr3 = weakPtr.lock();
        if (sharedPtr3 != nullptr) {
            std::cout << "*sharedPtr3: " << *sharedPtr3 << std::endl;
        }
        if (sharedPtr3 == nullptr) {
            std::cout << "空" << std::endl;
        }
        std::cout << "weakPtr.use_count(): " << weakPtr.use_count() << std::endl;
    }

    std::exit( 0 );
}